﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Objects.DataClasses;
using System.Runtime.Serialization;
using System.IO;
using System.Xml.Serialization;
using System.Reflection;
using System.Data.Objects;

namespace NotAClue.EF.Auditing
{
    public class AuditTrail
    {
        private string _connectionString; 

        public AuditTrail(String connectionString)
        {
            // new up the connection string
            _connectionString = connectionString;
        }

        /// <summary>
        /// Adds an audit entry to the database.
        /// </summary>
        /// <param name="entry">The entry.</param>
        /// <param name="userId">The user id.</param>
        public void AddAuditEntry(ObjectStateEntry entry, string userId)
        {
            using (var OC = new Models.AuditTrailContext(_connectionString))
            {
                if (entry.Entity is EntityObject)
                {
                    var auditEntry = new Models.AuditEntry
                        {
                            TableName = entry.Entity.ToString(),
                            RecordId = entry.EntityKey.ToString(),
                            State = (int)entry.State,
                            CreatedBy = userId,
                            CreatedOn = DateTime.Now
                        };

                    foreach (string propName in entry.GetModifiedProperties())
                    {
                        var auditEntryItem = new Models.AuditEntryItem
                            {
                                ColumnName = propName
                            };

                        auditEntry.AuditEntryItems.Add(auditEntryItem);

                        switch (entry.State)
                        {
                            case EntityState.Added:
                                auditEntryItem.NewValue = entry.CurrentValues[propName].ToString();
                                break;
                            case EntityState.Modified:
                                auditEntryItem.OldValue = entry.OriginalValues[propName].ToString();
                                auditEntryItem.NewValue = entry.CurrentValues[propName].ToString();
                                break;
                            case EntityState.Deleted:
                                auditEntryItem.OldValue = entry.OriginalValues[propName].ToString();
                                break;
                            default:
                                break;
                        }
                    }
                    OC.AuditEntries.Add(auditEntry);
                    OC.SaveChanges();
                }
            }
        }

        #region Audit Help Utility Class
        public void ProcessAuditFields(IEnumerable<Object> list, String userId, bool InsertMode = true)
        {
            foreach (ObjectStateEntry item in list)
            {
                // deal with insert and update entities
                var auditEntity = item.Entity as IAuditable;
                if (auditEntity != null)
                {
                    var now = DateTime.Now;
                    if (InsertMode)
                    {
                        auditEntity.CreatedBy = userId;
                        auditEntity.CreatedOn = now;
                    }

                    auditEntity.UpdatedBy = userId;
                    auditEntity.UpdatedOn = now;
                }
            }
        }
        #endregion
    }
}
